package com.test45_JUC;

import java.util.Map;
import java.util.concurrent.*;

/**
 * 数据缓存
 */
public class Demo24_CacheTest {

    public static void main(String[] args) throws Exception {
        Cache<Long, News> cache = new Cache<>();
        cache.put(1L, new News(1L, "沐言科技：www.yootk.com"));
        cache.put(2L, new News(2L, "李兴华高薪就业编程训练营：edu.yootk.com"));
        System.out.println(cache.get(1L));
        System.out.println(cache.get(2L));
        System.err.println("-------------- 清理分割线 --------------");
        TimeUnit.SECONDS.sleep(3);  // 3秒之后的数据一定被清除了
        System.out.println(cache.get(1L));
        System.out.println(cache.get(2L));
    }
}

/**
 * 新闻类
 */
class News {
    private long nid;
    private String title;

    public News(long nid, String title) {
        this.nid = nid;
        this.title = title;
    }

    @Override
    public String toString() {
        return "【新闻数据】新闻编号：" + this.nid + "，新闻标题：" + this.title;
    }
}

/**
 * 定义缓存类
 */
class Cache<K, V> {

    private Map<K, V> cacheObjects = new ConcurrentHashMap<>();  // 并发集合

    private static final long DELAY_SECOND = 2;  // 缓存时间

    private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;  // 时间单元

    private BlockingQueue<DelayedItem<Pair>> queue = new DelayQueue();

    public Cache() {
        // 创建数据清理的线程
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    DelayedItem<Pair> item = Cache.this.queue.take();
                    if (item != null) {
                        Pair pair = item.getItem();
                        Cache.this.cacheObjects.remove(pair.key, pair.value);
                    }
                } catch (Exception e) {}
            }
        });
        // 设置为守护线程
        thread.setDaemon(true);
        thread.start();
    }

    // 设置内容
    public void put(K key, V value) throws Exception {
        // 保存的同时返回旧的数据
        V oldValue = this.cacheObjects.put(key, value);
        // 所有的数据的内容是被保存在队列之中的，既然设置了内容，如果重复的时候应该更新时间
        if (oldValue != null) {
            this.queue.remove(oldValue);
        }
        this.queue.put(new DelayedItem<>(new Pair(key, value), DELAY_SECOND, TIME_UNIT));
    }

    // 获取数据
    public V get(K key) {
        return this.cacheObjects.get(key);
    }

    /**
     * 定义缓存的数据项
     */
    private class Pair {
        private K key;
        private V value;

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }

    private class DelayedItem<T> implements Delayed {
        private T item;  // 缓存项
        private long delay;  // 延迟时间
        private long start;  // 开始时间

        public DelayedItem(T item, long delay, TimeUnit timeUnit) {
            this.item = item;
            this.delay = TimeUnit.MILLISECONDS.convert(delay, timeUnit);    // 延迟时间
            this.start = System.currentTimeMillis();    // 当前时间
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert((this.start + this.delay)
                    - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        }

        public T getItem() {
            return item;
        }
    }
}
